/*
 * Copyright (c) 2005-2009, Messaging Logic. All Rights Reserved.
 */

package org.xi8ix.jdbc;

import java.sql.*;
import java.util.*;

/**
 * This class contains various standard SimpleStatement ResultMappers commonly required for trivial
 * statements and utility functions useful for building ResultMappers.
 *
 * @author Iain Shigeoka
 */
public class Mappers {

    /**
     * Converts a SQL timestamp object to a generic Java util Date object. Some frameworks (such as GWT)
     * do not support Date subclasses like Timestamp.
     *
     * @param ts the timestamp to convert
     * @return a "clean" java util Date object
     */
    public static java.util.Date convert(Timestamp ts) {
        if (ts == null) {
            return null;
        } else {
            return new java.util.Date(ts.getTime());
        }
    }

    /**
     * Converts a 1/0 integer value into a boolean. Useful for mapping int 0/1 fields to booolean values.
     *
     * @param value the value to convert
     * @return fales if the value is 0, true otherwise
     */
    public static boolean bool(int value) {
        return value != 0;
    }

    /**
     * Converts 'Y'/'N' varchar fields into boolean values.
     *
     * @param value the value to convert
     * @return true if the value is 'Y', 'y', 'T', or 't', false otherwise
     */
    public static boolean bool(String value) {
        return value.matches("[YyTt]");
    }

    /**
     * Returns a result mapper where the only item of interest in the result set is a string at index 1.
     *
     * @return a mapper that returns a single string result
     */
    public static ResultMapper<String> stringMapper() {
        return new ResultMapper<String>(){
            public String mapRow(ResultSet rs, int index) throws SQLException {
                return rs.getString(1);
            }
        };
    }

    /**
     * Returns a result mapper where the only item of interest in the result set is a string at index 1
     * and only one occurrance of a string is allowed within the list.
     *
     * @return a mapper that returns a single string result
     */
    public static ResultMapper<String> stringUniqueMapper() {
        return new ResultMapper<String>(){
            private HashSet<String> strings = new HashSet<String>();
            public String mapRow(ResultSet rs, int index) throws SQLException {
                String result = rs.getString(1);
                if (strings.contains(result)) {
                    return null;
                } else {
                    strings.add(result);
                    return result;
                }
            }
        };
    }

    /**
     * Returns a result mapper where the only item of interest in the result set is a string at index 1.
     *
     * @return a mapper that returns a single string result
     */
    public static ResultMapper<Long> longMapper() {
        return new ResultMapper<Long>(){
            public Long mapRow(ResultSet rs, int index) throws SQLException {
                return rs.getLong(1);
            }
        };
    }

    /**
     * A simple mapper that extracts rows to object arrays. The ObjectArrayResultMapper is useful
     * if there is no concrete java object to build, especially for simple results.
     *
     * @return a mapper that creates an object array for each row
     */
    public static ResultMapper<Object[]> objectMapper() {
        return new ResultMapper<Object[]>() {
            public Object[] mapRow(ResultSet rs, int index) throws SQLException {
                int count = rs.getMetaData().getColumnCount();
                Object[] result = new Object[count];
                for (int i = 0; i < count; i++) {
                    result[i] = rs.getObject(i+1);
                }
                return result;
            }
        };
    }

    /**
     * Creates a mapper that creates an associative map of the column names to object values.
     *
     * @return mapper transforming each row into an associative map of column name to object value
     */
    public static ResultMapper<Map<String,Object>> mapMapper() {
        return new MapMapper();
    }

    private static class MapMapper implements ResultMapper<Map<String,Object>> {
        private ArrayList<String> columns = null;

        public Map<String, Object> mapRow(ResultSet rs, int index) throws SQLException {
            if (columns == null) {
                ResultSetMetaData meta = rs.getMetaData();
                int size = meta.getColumnCount();
                columns = new ArrayList<String>(size);
                for (int i = 0; i < size; i++) {
                    columns.add(meta.getColumnLabel(i));
                }
            }
            HashMap<String,Object> map = new HashMap<String,Object>(columns.size());
            for (String column: columns) {
                map.put(column,rs.getObject(column));
            }
            return map;
        }
    }
}
